/*
 * YIQOp.java
 */
package com.photoexpert;

import java.awt.RenderingHints;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ColorModel;

/**
 *
 * @author PANYIXIN
 */
public class YIQOp implements BufferedImageOp {

    public YIQOp(float yScale, float yOffset,
         float iScale, float iOffset,
         float qScale, float qOffset,
         RenderingHints hints)
    {
        _scale[0] = yScale;
        _scale[1] = iScale;
        _scale[2] = qScale;
        _offset[0] = yOffset;
        _offset[1] = iOffset;
        _offset[2] = qOffset;
        _hints = hints;
    }

    public final static double[][] RGB2YIQ = {
        {0.2990d, 0.5870d, 0.1140d},
        {0.595716d, -0.274453d, -0.321263d},
        {0.211456d, -0.522591d, 0.311135d}
    };
    public final static double[][] YIQ2RGB = {
        {1d, 0.9563d, 0.6210d},
        {1d, -0.2721d, -0.6474d},
        {1d, -1.1070d, 1.7046d}
    };
    private float[]                 _scale = {1f, 1f, 1f};
    private float[]                 _offset = {0f, 0f, 0f};
    private RenderingHints          _hints;

    @Override
    public BufferedImage filter(BufferedImage src, BufferedImage dest) {
        if(dest == null)
            dest = createCompatibleDestImage(src, src.getColorModel());
        int width = src.getWidth();
        int height = src.getHeight();
        for(int m = 0; m < width; ++m)
            for(int n = 0; n < height; ++n)
            {
                int rgb = src.getRGB(m, n);
                int r = (rgb & 0x00ff0000) >> 16;
                int g = (rgb & 0x0000ff00) >> 8;
                int b = rgb & 0x000000ff;
                double y =
                    (RGB2YIQ[0][0] * r + RGB2YIQ[0][1] * g + RGB2YIQ[0][2] * b)
                        * _scale[0] + _offset[0];
                double i =
                    (RGB2YIQ[1][0] * r + RGB2YIQ[1][1] * g + RGB2YIQ[1][2] * b)
                        * _scale[1] + _offset[1];
                double q =
                    (RGB2YIQ[2][0] * r + RGB2YIQ[2][1] * g + RGB2YIQ[2][2] * b)
                        * _scale[2] + _offset[2];
                r = (int)(YIQ2RGB[0][0] * y + YIQ2RGB[0][1] * i + YIQ2RGB[0][2] * q);
                g = (int)(YIQ2RGB[1][0] * y + YIQ2RGB[1][1] * i + YIQ2RGB[1][2] * q);
                b = (int)(YIQ2RGB[2][0] * y + YIQ2RGB[2][1] * i + YIQ2RGB[2][2] * q);
                if(r < 0) r = 0;
                if(r > 255) r = 255;
                if(g < 0) g = 0;
                if(g > 255) g = 255;
                if(b < 0) b = 0;
                if(b > 255) b = 255;
                rgb = (r << 16) + (g << 8) + b;
                rgb |= 0xff000000;
                dest.setRGB(m, n, rgb);
            }
        return dest;
    }

    @Override
    public Rectangle2D getBounds2D(BufferedImage src) {
        return src.getRaster().getBounds();
    }

    @Override
    public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM) {
        BufferedImage image;
        if (destCM == null) {
            ColorModel cm = src.getColorModel();
            image = new BufferedImage(cm,
                src.getRaster().createCompatibleWritableRaster(),
                cm.isAlphaPremultiplied(),
                null);
        } else {
            int w = src.getWidth();
            int h = src.getHeight();
            image = new BufferedImage (
                destCM,
                destCM.createCompatibleWritableRaster(w, h),
                destCM.isAlphaPremultiplied(),
                null);
        }

        return image;
    }

    @Override
    public Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
        if (dstPt == null) {
            dstPt = new Point2D.Float();
        }
        dstPt.setLocation(srcPt.getX(), srcPt.getY());
        return dstPt;
    }

    @Override
    public RenderingHints getRenderingHints() {
        return _hints;
    }
}
